using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SimianReshaper;
using System.IO;
using System.Collections.ObjectModel;
using System.Threading;
using System.Text.RegularExpressions;
using ICSharpCode.TextEditor.Document;
using System.Diagnostics;

namespace SimianReshaperUI
{
	public partial class MainFrame : Form
	{
		#region Const
		const string xmlFilePath = "Preferences.xml";
		const string simianArgumentsForFolders = @"-includes=**/*.cs -threshold={0}";
		const string simianArgumentsForFiles = "{0} -threshold={1}";
		const string visualStudioOpenString = @"/edit {0}";
		const float textEditorOverScrollScaleFactor = 0.0571f;
		#endregion

		#region Fields
		Preferences preferences;
		BackgroundWorker worker;
		HighlightGroup highLightGroup;

		string workingDirectory;
		string simianArgs;
		#endregion

		#region Constructors
		public MainFrame()
		{
			InitializeComponent();
			this.trvMain.Nodes.Clear();
			this.preferences = Preferences.Deseralize(Path.Combine(Application.StartupPath, xmlFilePath));
			this.highLightGroup = new HighlightGroup(this.txtEditorConrtol);
			this.txtEditorConrtol.Document.ReadOnly = true;
		}
		#endregion

		#region Private methods
		private void UpdateViewWithResults(RunResults runResults)
		{
			this.trvMain.BeginUpdate();
			Collection<DuplicationEntity> entityList = new Collection<DuplicationEntity>();
			SupportiveFunctions.ReformatErrors(runResults.Output, preferences, entityList);
			this.trvMain.Nodes.Clear();
			// fill tree view
			foreach (DuplicationEntity entity in entityList)
			{
				TreeNode header = new TreeNode();
				header.BackColor = Color.Pink;
				header.Text = entity.Header;
				header.Tag = entity;
				foreach (DuplicatedLocation duplicatedLocation in entity.DuplicationMessages)
				{
					TreeNode childNode = new TreeNode();
					childNode.Text = string.Format("{0}:({1} - {2})",
						duplicatedLocation.FileName,
						duplicatedLocation.FromLine,
						duplicatedLocation.ToLine);
					childNode.NodeFont = new Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
					childNode.Tag = duplicatedLocation;
					header.Nodes.Add(childNode);
				}
				this.trvMain.Nodes.Add(header);
			}
			this.trvMain.ExpandAll();
			if (this.trvMain.Nodes.Count > 0)
			{
				this.trvMain.Nodes[0].EnsureVisible();
			}
			this.trvMain.EndUpdate();
		}

		private static void OpenInVisualStudio(string executablePath,
			string arguments,
			string workingDirectory)
		{
			using (Process proc = new Process())
			{
				proc.StartInfo.FileName = executablePath;
				proc.StartInfo.Arguments = arguments;
				proc.StartInfo.WorkingDirectory = workingDirectory;
				proc.StartInfo.UseShellExecute = false;
				proc.StartInfo.CreateNoWindow = false;
				proc.StartInfo.RedirectStandardOutput = true;
				proc.StartInfo.RedirectStandardError = true;
				proc.Start();
				proc.WaitForExit();
			}
		}
		#endregion

		#region UI event handlers
		private void ignoreListToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.trvMain.Nodes.Clear();
			foreach (string output in this.preferences.IgnoreList)
			{
				this.trvMain.Nodes.Add(output);
			}
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (this.folderBrowserDlg.ShowDialog() == DialogResult.OK)
			{
				this.workingDirectory = this.folderBrowserDlg.SelectedPath;
				this.simianArgs = string.Format(simianArgumentsForFolders, preferences.Threshold);
				CalculateDuplicatesAndRefresh(this.simianArgs, this.workingDirectory);
				this.txtFileName.Text = this.workingDirectory;
			}
		}

		private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (this.fileOpenDlg.ShowDialog() == DialogResult.OK)
			{
				this.workingDirectory = Path.GetDirectoryName(this.fileOpenDlg.FileName);
				string filePath = this.fileOpenDlg.FileName;
				this.simianArgs = string.Format(simianArgumentsForFiles, Path.GetFileName(filePath), preferences.Threshold);
				CalculateDuplicatesAndRefresh(this.simianArgs, this.workingDirectory);
				this.txtFileName.Text = filePath;
			}
		}

		private void CalculateDuplicatesAndRefresh(string simianArgsy, string workingDirector)
		{
			RunResults runResults = null;
			ProgressForm progressDialog = new ProgressForm();

			this.worker = new BackgroundWorker();
			this.worker.DoWork += new DoWorkEventHandler(delegate(object backWorker, DoWorkEventArgs eventArgs)
			{
				runResults = SupportiveFunctions.RunExecutable(Path.Combine(Application.StartupPath, "simian-2.3.33.exe"),
				simianArgs,
				workingDirectory);
			});
			this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate(object backWorker, RunWorkerCompletedEventArgs eventArgs)
			{
				progressDialog.Close();
			});

			if (!this.worker.IsBusy)
			{
				this.worker.RunWorkerAsync();
			}
			progressDialog.ShowDialog();

			if (runResults.RunException != null)
			{
				MessageBox.Show("Error occured while parsing the files");
			}
			else
			{
				UpdateViewWithResults(runResults);
			}
		}

		private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
		{
			SettingsDialog settingsDlg = new SettingsDialog(this.preferences);
			if (settingsDlg.ShowDialog() == DialogResult.OK)
			{
				this.preferences = settingsDlg.Preferences;
				this.preferences.Serialize(Path.Combine(Application.StartupPath, xmlFilePath));
			}
		}

		private void btnRefresh_Click(object sender, EventArgs e)
		{
			if (!string.IsNullOrEmpty(this.workingDirectory)
				&& Directory.Exists(this.workingDirectory)
				&& !string.IsNullOrEmpty(this.simianArgs))
			{
				CalculateDuplicatesAndRefresh(this.simianArgs, this.workingDirectory);
			}
		}

		private void trvMain_AfterSelect(object sender, TreeViewEventArgs e)
		{
			if (this.trvMain.SelectedNode != null)
			{
				DuplicatedLocation duplicatedLocation = this.trvMain.SelectedNode.Tag as DuplicatedLocation;
				if (duplicatedLocation != null)
				{
					string path = duplicatedLocation.FileName;
					int fromLine = duplicatedLocation.FromLine;
					int toLine = duplicatedLocation.ToLine;

					if (File.Exists(path))
					{
						TextReader reader = new StreamReader(path);
						this.txtEditorConrtol.Document.TextContent = reader.ReadToEnd();
						this.highLightGroup.ClearMarkers();

						int startOffset = this.txtEditorConrtol.Document.LineSegmentCollection[fromLine - 1].Offset;
						int endOffset = this.txtEditorConrtol.Document.LineSegmentCollection[toLine - 1].Offset +
							this.txtEditorConrtol.Document.LineSegmentCollection[toLine - 1].Length;
						TextMarker marker = new TextMarker(startOffset,
							endOffset - startOffset,
							TextMarkerType.SolidBlock,
							Color.LightGreen,
							Color.Black);
						highLightGroup.AddMarker(marker);
						int numberOfLinesToAppend = (int)(textEditorOverScrollScaleFactor * this.txtEditorConrtol.Height);
						int lastIndex = this.txtEditorConrtol.Document.LineSegmentCollection.Count - 1;
						if (fromLine + numberOfLinesToAppend - 1 > lastIndex)
						{
							this.txtEditorConrtol.ActiveTextAreaControl.Caret.Position = new ICSharpCode.TextEditor.TextLocation(0, lastIndex);
						}
						else
						{
							this.txtEditorConrtol.ActiveTextAreaControl.Caret.Position = new ICSharpCode.TextEditor.TextLocation(0, fromLine + numberOfLinesToAppend - 1);
						}
						this.txtEditorConrtol.Focus();
						this.txtEditorConrtol.Refresh();
					}
				}
			}
		}

		private void btnClose_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void trvMain_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
		{
			DuplicatedLocation duplicatedLocation = e.Node.Tag as DuplicatedLocation;
			if (duplicatedLocation != null)
			{
				OpenInVisualStudio(@"C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe",
					string.Format(visualStudioOpenString, Path.GetFileName(duplicatedLocation.FileName)),
					Path.GetDirectoryName(duplicatedLocation.FileName));
			}
		}

		#endregion
	}
}